/*
 * Copyright (C) 2020 The LINN Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.juqimiao.linn.exception;

import com.juqimiao.linn.transfer.Command;
import com.juqimiao.linn.transfer.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 默认异常处理类。
 *
 * @author  Collin Cai
 */
public class DefaultExceptionHandler implements ExceptionHandlerI {

    //---- Static Fields ----------/

    private static DefaultExceptionHandler SINGLE_INSTANCE = null;
    private static final String ERROR_MSG_TEMPLATE = "Process { %s } failed, errorCode: %s errorMsg: %s";
    //---- Static Method ----------/

    /**
     * 构建并返回单例对象，线程安全。
     *
     * @return {@link DefaultExceptionHandler} 实例。
     */
    public static synchronized DefaultExceptionHandler getInstance() {
        if (SINGLE_INSTANCE == null) {
            synchronized (DefaultExceptionHandler.class) {
                if (SINGLE_INSTANCE == null) {
                    SINGLE_INSTANCE = new DefaultExceptionHandler();
                }
            }
        }
        return SINGLE_INSTANCE;
    }

    /**
     * Todo: Refactor Logger function. shoule be customized factory, It not slf4j's factory.
     */
    //---- Fields ----------/

    private Logger logger = LoggerFactory.getLogger(DefaultExceptionHandler.class);

    //---- Methods ----------/

    /**
     * 通过异常，构建包含错误信息的{@link Response}对象。
     *
     * @param command   一个命令对象。
     * @param response  一个响应对象。
     * @param exception 一个异常对象。
     */
    @Override
    public void handleException(Command command, Response response, Exception exception) {
        buildResponse(response, exception);
        printLog(command, response, exception);
    }

    /**
     * 构建响应对象。
     *
     * @param response  一个响应对象。
     * @param exception 一个异常对象。
     */
    private void buildResponse(Response response, Exception exception) {
        if (exception instanceof BaseException) {
            ErrorI error = ((BaseException) exception).getError();
            response.setErrorCode(error.getErrorCode());
        } else {
            response.setErrorCode(BasicError.SYSTEM_ERROR.getErrorCode());
        }

        response.setErrorMessage(exception.getMessage());

        response.setSuccess(false);
    }

    /**
     * 构建错误信息。
     *
     * @param baseCommand  一个命令对象。
     * @param response 一个响应对象。
     * @return 错误信息。
     */
    private String buildErrorMsg(Command baseCommand, Response response) {

        return String.format(ERROR_MSG_TEMPLATE,
                baseCommand,
                response.getErrorCode(),
                response.getErrorMessage());
    }

    /**
     * Todo： 思考是否需要在这里实现日志打印功能。
     */
    private void printLog(Command cmd, Response response, Exception exception) {
        if (exception instanceof BaseException) {
            //biz exception is expected, only warn it
            logger.warn(buildErrorMsg(cmd, response));
        } else {
            //sys exception should be monitored, and pay attention to it
            logger.error(buildErrorMsg(cmd, response), exception);
        }
    }
}
